<template>
	<rui-pages>
		<view class="ota">
			<view class="ota_title">
				{{message?.title || 'OTA Title'}}
			</view>
			<view class="ota_desc">
				{{message.desc || 'OTA Desc'}}
			</view>
			<block v-if="status.is_ota">
				<!-- 未连接 -->
				<block v-if="!status.connect">
					<button class="ota_btn" @click="connect" :disabled="status.button">
						{{status.text}}
					</button>
				</block>

				<!-- 已连接 -->
				<block v-else>
					<!-- 连接状态 -->
					<button class="ota_btn" @click="start" v-if="!status.start">
						{{status.text}}
					</button>
					<!-- 显示进度 -->
					<view class="ota_chart" v-else>
						<rui-charts-wave color="#67c8f2" :progress="progress.done" size="300rpx"></rui-charts-wave>
					</view>
				</block>
			</block>
		</view>


	</rui-pages>
</template>

<script setup>
	import {
		ref
	} from 'vue';

	import {
		onLoad,
		onUnload
	} from "@dcloudio/uni-app"

	import {
		getVersion,
	} from "@/common/api.js"
	import {
		_setBuffer,
		_handleBuffer,
		_chunkArray
	} from "@/util/common.js"

	import ble from "@/util/ble.js"
	import {
		productStore
	} from "@/store"

	let product = productStore()
	let interval;
	let message = ref({})
	let status = ref({
		is_ota: false,
		connect: false,
		start: false,
		state: false,
		text: "连接蓝牙",
		button: false,
	})
	let progress = ref({
		pages: 0,
		count: 0,
		done: 0
	});
	let upload = {
		packet: 500,
		addr: 0,
		pages: 0,
		count: 0,
		done: false,
	}
	let erase = {
		addr: 0,
		pages: 0,
		count: 0
	}

	const CMD_BASE = "00"
	const CMD_START = "01"
	const CMD_ERASE = "03"
	const CMD_UPLOAD = "05"
	const CMD_END = "09"


	onUnload(() => {
		//关闭屏幕常亮
		uni.setKeepScreenOn({
			keepScreenOn: false
		});
		clearInterval(interval)
		ble.watch = function() {}
		ble.error = function() {}
	})

	onLoad(() => {
		//保持屏幕常亮
		uni.setKeepScreenOn({
			keepScreenOn: true
		});
		//获取详情
		getVerInfo()
	})

	const onBle = () => {
		//监听事件
		ble.error = (event, d) => {
			console.log(event, d)
			if (d.code == 10012) {
				onConnected(false, '设备连接超时，是否重连')
			}
		}
		let state_num = 0;
		ble.watch = (event, d) => {
			console.log(event, d)

			if (event == 'state2') {
				status.value.text = `请触摸指纹激活水杯 ${d.remainder}s`
			}

			if (event == 'state') {
				// state_num++;
				// if(!upload.done) return false;
				// console.log(1111111, upload.done)
				// status.value.connect = d.connected;
				// status.value.text = d.connected ? "开始升级":"设备断开"

				// if(state_num > 0 && !d.connected) return false;
				// onConnected(d.connected, '设备已断开连接，是否重连')
			}

			if (event == 'start') {
				status.value.text = "开始升级"
				status.value.connect = true;
				start();
			}

			if (event == 'notify') {
				if (d.command == CMD_BASE) {
					ble.send(createBuffer({
						command: CMD_START,
						len: 3
					}), '', 100)
				}
				if (d.command == CMD_START) {
					// //存储起始地址
					erase.addr = parseInt(d.data.slice(0, 4).join(""), 16);
					upload.addr = parseInt(d.data.slice(0, 4).join(""), 16);
					console.log('存储起始地址', erase.addr, upload.addr)

					status.value.start = true;
					cmd_erase();
				}
			}
		}
	}

	const onConnected = (state, content) => {
		if (state && status.value.connect) return;
		status.value.connect = false;
		status.value.text = "设备断开"
		uni.showModal({
			title: '系统提示',
			content,
			confirmText: "重连设备",
			cancelText: "退出",
			success: function(res) {
				if (res.confirm) {
					ble.connect()
				} else if (res.cancel) {
					uni.switchTab({
						url: "/pages/tabbar/index/index"
					})
				}
			}
		});
	}

	const connect = () => {
		status.value.button = true;
		status.value.text = "蓝牙加载中..."
		onBle();
		ble.config({
			deviceId: product.getInfo.deviceId,
			serviceId: "02F00000-0000-0000-0000-00000000FE00",
			properties(type, uuid) {
				if (type == 'write') {
					return uuid.includes("FF01")
				}
				if (type == 'notify') {
					return uuid.includes("FF02")
				}
			}
		})

		//断开连接
		ble.closeAll(() => {
			ble.init(() => {
				setTimeout(_ => {
					console.log('连接蓝牙')
					ble.connect();
				}, 500)
			})

		})
	}


	const getVerInfo = (callback) => {
		getVersion({
			product_id: product.getInfo.product_id
		}).then(res => {
			//检测版本
			if (product.getVersion >= res.data.version) {
				message.value = {
					title: `您已是最新固件版本`,
					desc: `您当前版本1.0.${product.getVersion},无需更新请返回。`
				}
				return false;
			}
			status.value.is_ota = true;
			message.value = {
				title: `最新固件版本1.0.${res.data.version}`,
				desc: `您当前版本1.0.${product.getVersion}, ${res.data.content}。`
			}
			downFile(res.data.path);
			if (typeof callback == 'function') {
				callback()
			}
		})
	}

	const downFile = (url) => {
		uni.request({
			url,
			method: 'GET',
			responseType: 'arraybuffer', // 设置响应类型为 arraybuffer  
			success: function(res) {
				if (res.statusCode === 200) {
					let binDataView = _setBuffer(res.data, upload.packet)

					upload.len = binDataView.len;
					upload.crc = binDataView.crc;
					upload.pages = binDataView.data.length;
					upload.data = binDataView.data;
					erase.pages = Math.floor(upload.len / 4096);
					if (upload.len % 4096 !== 0) {
						erase.pages += 1
					}

					progress.value.pages = upload.pages + erase.pages;
					console.log(2222, erase, upload)
				}
			}
		});
	}


	const start = () => {
		if (erase.pages <= 0) return;
		message.value = {
			title: `正在升级中,请耐心等候...`,
			desc: `固件升级过程中，请勿关闭页面否者会升级失败。`
		}
		ble.send(createBuffer({
			command: CMD_BASE,
			len: 3
		}), '', 100)
	}


	const cmd_erase = () => {
		let buffer = createBuffer({
			command: CMD_ERASE,
			len: 7,
			addr: erase.addr
		})
		erase.addr = erase.addr + 4096;
		erase.count++;
		ble.send(buffer, () => {
			if (erase.count < erase.pages) {
				cmd_erase()
			} else {
				cmd_upload()
				console.log('开始升级', upload)
			}
			progress.value.count++;
			setProgress()
		}, 50)
	}


	const cmd_upload = () => {
		let dd = upload.data[upload.count];
		let packet = dd ? dd.length : 0;
		let buffer = createBuffer({
			command: CMD_UPLOAD,
			len: 9,
			addr: upload.addr,
			packet,
			data: upload.data[upload.count]
		})
		upload.addr += packet;
		upload.count++;

		ble.send(buffer, () => {
			if (upload.data[upload.count]) {
				cmd_upload()
			} else {
				upload.done = true;
				console.log("升级结束")
				setTimeout(() => {
					cmd_end()
				}, 200)
			}
			progress.value.count++;
			setProgress()
		}, 60)
	}

	const cmd_end = () => {
		status.value.text = "升级完成"
		message.value = {
			title: `恭喜您升级成功`,
			desc: `您已成功升级到最新版本，5秒后返回首页。`
		}
		// setTimeout(_ => {
		// 	clearInterval(interval)
		// 	ble.close()
		// 	uni.switchTab({
		// 		url: "/pages/tabbar/index/index"
		// 	})
		// }, 6000)
		let number = 5;
		interval = setInterval(_ => {
			message.value.desc = `您已成功升级到最新版本，${number}秒后返回首页。`
			number --;
			if(number <= 0) {
				clearInterval(interval)
				ble.close()
				uni.switchTab({
					url: "/pages/tabbar/index/index"
				})
			}
		}, 1000)
		
		let buffer = createBuffer({
			command: CMD_END,
			len: 10,
			bin_length: upload.len,
			crc: upload.crc
		})
		ble.send(buffer)
	}

	const setProgress = () => {
		//完成进度
		progress.value.done = (progress.value.count / progress.value.pages * 100) >> 0;
	}
	const createBuffer = (option) => {
		option.command = _handleBuffer(option.command, 1)
		option.len = _handleBuffer(option.len, 2)
		if (option.addr || option.addr == 0) {
			option.addr = _handleBuffer(option.addr, 4)
		}

		let hex_str = [];
		switch (option.command[0]) {
			case CMD_START:
				hex_str = [...option.command, ...option.len, '00000000']
				break;
			case CMD_ERASE:
				hex_str = [...option.command, ...option.len, ...option.addr]
				break;
			case CMD_UPLOAD:
				option.packet = _handleBuffer(option.packet, 2)
				hex_str = [...option.command, ...option.len, ...option.addr, ...option.packet, ...option.data]
				break;
			case CMD_END:
				option.crc = _handleBuffer(option.crc, 4)
				option.bin_length = _handleBuffer(option.bin_length, 4)
				hex_str = [...option.command, ...option.len, ...option.bin_length, ...option.crc]
				break;
			default:
				hex_str = [...option.command, ...option.len, '00000000']
		}
		// console.log('hex_str', option, hex_str)
		let typedArray = new Uint8Array(hex_str.map(function(h) {
			return parseInt(h, 16)
		}))
		return typedArray.buffer
	}
</script>


<style lang="scss" scoped>
	.ota {
		margin: 150rpx 30rpx;

		&_btn {
			background: #67c8f2;
			width: 80%;
			height: 80rpx;
			color: #fff;
			text-align: center;
			line-height: 80rpx;
			border-radius: 20rpx;
			margin: 100rpx auto;

			&::after {
				border: none;
			}

		}

		&_title {
			text-align: center;
			font-weight: bold;
			font-size: 38rpx;
		}

		&_desc {
			font-size: 24rpx;
			color: #999;
			text-align: center;
			margin-top: 10rpx;
		}

		&_chart {
			display: flex;
			justify-content: center;
			margin-top: 150rpx;
		}
	}
</style>